package com.wdb.utils;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.*;
import org.springframework.stereotype.Component;

import java.util.HashSet;
import java.util.concurrent.TimeUnit;

/**
 * redis工具类
 *
 * @author: wendaobai@qq.com
 * @date: 2024/1/5 0005 9:41
 */
@Component
public class RedisUtils {
  private static final Logger log = LoggerFactory.getLogger(RedisUtils.class);
  @Autowired RedisTemplate<Object, Object> redisTemplate;

  /**
   * 普通缓存放入
   *
   * @param key
   * @param value
   * @return
   */
  public boolean set(String key, Object value) {
    try {
      redisTemplate.opsForValue().set(key, value);
      return true;
    } catch (Exception e) {
      log.error(e.getMessage(), e);
      return false;
    }
  }

  /**
   * 普通缓存放入并设置时间
   *
   * @param key
   * @param value
   * @param time 时间（秒）,time要大于0 如果time小于等于0 将设置无限期，注意:这里将会替换原有的时间
   * @return true or false
   */
  public boolean set(String key, Object value, long time) {
    try {
      if (time > 0) {
        redisTemplate.opsForValue().set(key, value, time, TimeUnit.SECONDS);
      } else {
        set(key, value);
      }
      return true;
    } catch (Exception e) {
      log.error(e.getMessage(), e);
      return false;
    }
  }

  /**
   * 普通缓存放入并设置时间
   *
   * @param key
   * @param value
   * @param time
   * @param timeUnit
   * @return
   */
  public boolean set(String key, Object value, long time, TimeUnit timeUnit) {
    try {
      if (time > 0) {
        redisTemplate.opsForValue().set(key, value, time, timeUnit);
      } else {
        set(key, value);
      }
      return true;
    } catch (Exception e) {
      log.error(e.getMessage(), e);
      return false;
    }
  }

  /**
   * 普通缓存获取
   *
   * @param key
   * @return
   */
  public Object get(String key) {
    return key == null ? null : redisTemplate.opsForValue().get(key);
  }

  /**
   * 删除缓存
   *
   * @param keys 可以传一个值 或多个
   */
  public void del(String... keys) {
    if (keys != null && keys.length > 0) {
      if (keys.length == 1) {
        Boolean result = redisTemplate.delete(keys[0]);
        log.debug("--------------------------------------------");
        log.debug(
            new StringBuilder("删除缓存：").append(keys[0]).append("，结果：").append(result).toString());
        log.debug("--------------------------------------------");

      } else {
        // 批量删除
        HashSet<Object> keySet = new HashSet<>();
        for (String key : keys) {
          if (redisTemplate.hasKey(key)) {
            keySet.add(key);
          }
        }
        Long count = redisTemplate.delete(keySet);
        log.debug("--------------------------------------------");
        log.debug("成功删除缓存：" + keySet.toString());
        log.debug("缓存删除数量：" + count + "个");
        log.debug("--------------------------------------------");
      }
    }
  }

  /**
   * 批量模糊删除key
   *
   * @param pattern
   */
  public void scanDel(String pattern) {
    ScanOptions options = ScanOptions.scanOptions().match(pattern).build();
    try (Cursor<byte[]> cursor =
        redisTemplate.executeWithStickyConnection(
            (RedisCallback<Cursor<byte[]>>)
                connection ->
                    (Cursor<byte[]>)
                        new ConvertingCursor<>(
                            connection.scan(options),
                            redisTemplate.getKeySerializer()::deserialize))) {
      while (cursor.hasNext()) {
        redisTemplate.delete(cursor.next());
      }
    }
  }
  /**
   * 根据 key 获取过期时间
   *
   * @param key 键 不能为null
   * @return 时间(秒) 返回0代表为永久有效
   */
  public long getExpire(Object key) {
    return redisTemplate.getExpire(key, TimeUnit.SECONDS);
  }

  /**
   * 指定缓存失效时间
   *
   * @param key 键
   * @param time 时间(秒) 注意:这里将会替换原有的时间
   * @param timeUnit 单位
   */
  public boolean expire(String key, long time, TimeUnit timeUnit) {
    try {
      if (time > 0) {
        redisTemplate.expire(key, time, timeUnit);
      }
    } catch (Exception e) {
      log.error(e.getMessage(), e);
      return false;
    }
    return true;
  }
}
